using M13.Math;
using M13.Utility;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using M13.DataStructure;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace M13.Game.World
{
    public class RegionBulider
    {
        public Vector2Int RegionLocalCoord { get; private set; }
        private int _chunkIndex = 0;
        private SaveConfig _saveConfig;
        private WorldBuildConfig _buildConfig;

        public List<Vector2Int> chunkCoordList = new List<Vector2Int>();
        public List<ChunkDataBoot> chunkDataBoots = new List<ChunkDataBoot>();

        /// <summary>
        /// һ��ѹ�����ݣ�δ����������
        /// </summary>
        private List<byte> _regionSingularCompressedData  = new List<byte>();

        /// <summary>
        /// region����������
        /// </summary>
        public byte[] RegionBoot { get; private set; }
        
        int _dataOffset = 0;
        private Stopwatch _stopwatch = new Stopwatch();

        
        static byte[] _continentMap = new byte[256];
        static byte[] _heightMap = new byte[256];
        static byte[] _turfIdMap = new byte[16384];

        public RegionBulider(Vector2Int regionLocalCoord,SaveConfig saveConfig, WorldBuildConfig buildConfig)
        {
            this.RegionLocalCoord = regionLocalCoord;
            _saveConfig = saveConfig;
            _buildConfig = buildConfig;
            ChunksCoord();
            Array.Clear(_heightMap, 0, _heightMap.Length);
            Array.Clear( _continentMap, 0, _continentMap.Length);
            Array.Clear(_turfIdMap, 0, _turfIdMap.Length);
        }

        private void ChunksCoord()
        {
            for (int x = RegionLocalCoord.x * WorldConstant.RegionSideLengthNumber; x < (RegionLocalCoord.x + 1) * WorldConstant.RegionSideLengthNumber; x++) 
            {
                for (int y = RegionLocalCoord.y * WorldConstant.RegionSideLengthNumber; y < (RegionLocalCoord.y + 1) * WorldConstant.RegionSideLengthNumber; y++)
                {
                    chunkCoordList.Add(new Vector2Int(x, y));
                }
            }
        }

        public bool ChunksOfRegionGenerateFinished()
        {
            return _chunkIndex == (chunkCoordList.Count);
        }

        public void GenerateChunkData()
        {
            HeightValueGenerate(chunkCoordList[_chunkIndex], _saveConfig.seed, _buildConfig);
            TurfIdMapGenerate(chunkCoordList[_chunkIndex], _heightMap);

            /*
             * �����Ƿ�ʹ�� RegionDataArray ������л�����
             * Ŀǰ����������û��̫��Ӱ�� 24.10.12
             */


            byte[] compressedContinentMap = Clzf2.Compress(_continentMap);
            byte[] compressedHeightMap = Clzf2.Compress(_heightMap);
            byte[] compressedTurfIdMap = Clzf2.Compress(_turfIdMap);

            _regionSingularCompressedData.AddRange(compressedContinentMap);
            _regionSingularCompressedData.AddRange(compressedHeightMap);
            _regionSingularCompressedData.AddRange(compressedTurfIdMap);

            chunkDataBoots.Add(new ChunkDataBoot(compressedContinentMap.Length, compressedHeightMap.Length, compressedTurfIdMap.Length, _dataOffset, DateTime.Now.Ticks));
            _dataOffset += chunkDataBoots[_chunkIndex].GetTotalLength();

             _chunkIndex++;
        }

        public byte[] GetRegionBootOnFinished()
        {
            RegionBoot = DataBootSerializer.Serializer(chunkDataBoots);
            return RegionBoot;
        }
        public byte[] GetRegionDataOnFinished()
        {
            return _regionSingularCompressedData.ToArray();
        }

        /// <summary>
        /// ���ɴ�½ֵ����½ֵ�������ִ�½�뺣�󣬴�½Ϊ(��ֵ~1)������Ϊ0
        /// </summary>
        /// <param name="chunkLocalCoord"></param>
        /// <returns></returns>
        private static void HeightValueGenerate(Vector2Int chunkLocalCoord, int seed, WorldBuildConfig worldBuildConfig)
        {
            Vector2 org = new Vector2(seed / (Mathf.Sqrt(Mathf.Abs(seed + 0.10516f)) + 0.10516f), -seed / (Mathf.Sqrt(Mathf.Abs(seed + 0.10516f))) + 0.10516f);

            Vector2Int mapCoord = ChunkToMapCoord(worldBuildConfig.worldSizeLength, chunkLocalCoord);
            int i = 0;
            for (int x = mapCoord.x * 16; x < mapCoord.x * 16 + 16; x++)
            {
                for (int y = mapCoord.y * 16; y < mapCoord.y * 16 + 16; y++, i++)
                {
                    float f = Noise.GetContinentalShelf(x, y, org, worldBuildConfig.worldSizeLength, 0.141f, 0.304f, 4);
                    _continentMap[i] = f == 0 ? (byte)0 : (byte)1;
                    if (f > 1f) Debug.LogError("������ֵ����½ֵ����1");
                    _heightMap[i] = (byte)(f * WorldConstant.MaxTurfHeightNumber / 2);
                }
            }
        }

        private static void TurfIdMapGenerate(Vector2Int chunkLocalCoord, byte[] h)
        {
            for (int x = 0; x < 16; x++)
            {
                for (int z = 0; z < 16; z++)
                {
                    for (int y = 0; y < 64; y++)
                    {
                        _turfIdMap[M13Mathf.XZYToIndex(new Vector3Int(x, y, z))] = GetTurf(y, h[M13Mathf.XYToIndex(new Vector2Int(x, z))]);
                    }
                }
            }
        }

        private static byte GetTurf(Vector3 turfPos, byte height)
        {
            return turfPos.y > height ? (turfPos.y <= 2f ? (byte)1 : (byte)0) : (byte)3;
        }

        private static byte GetTurf(int y, byte height)
        {
            return y > height ? (byte)0 : (byte)2;
        }

        private static Vector2Int ChunkToMapCoord(int worldSizeLength, Vector2Int chunkLocalCoord)
        {
            return new Vector2Int(worldSizeLength / 32 + chunkLocalCoord.x, worldSizeLength / 32 + chunkLocalCoord.y);
        }
    }
}